﻿
using Crgd.UAuthServer.Sdk;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Microsoft.Net.Http.Headers;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;

namespace Microsoft.Extensions.DependencyInjection
{
    public static class UAuthServerServiceCollectionExtensions
    {

        private const string UAuthServerApiName = "UAuth Server Api";
        private const string UAuthUserAuthApiName = "UAuth User Auth Api";

        public static IServiceCollection AddUAuthServer<
            TUserManager,
            TAppManager,
            TSecretKeyManager,
            TAppPermissionManager,
            TUserPermissionManager,
            TTenantManager,
            TDomainManager
            >(
                this IServiceCollection services,
                Action<UserAuthenticationOptions> configureAuth,
                Action<UAuthServerOptions> configureServer
            )
            where TAppManager : class, IAppManager
            where TAppPermissionManager : class, IAppPermissionManager
            where TUserPermissionManager : class, IUserPermissionManager
            where TSecretKeyManager : class, IAppSecretKeyManager
            where TUserManager : class, IUserManager
            where TTenantManager: class, ITenantManager
            where TDomainManager: class, IDomainManager
        {
            if (configureServer == null)
            {
                throw new ArgumentNullException(nameof(configureServer));
            }
            services.AddHttpContextAccessor();
            services.AddCrgdAppAuth(options =>
            {
                options.GetSecretKeyAsync = async (serviceProvider, appkey) =>
                {
                    var mgr = serviceProvider.GetRequiredService<IAppSecretKeyManager>();
                    var uauthOpts = serviceProvider.GetRequiredService<IOptions<UAuthServerOptions>>().Value;
                    return await mgr.GetMutualSecretKeyAsync(appkey, uauthOpts.ServerAppKey);
                };
            });
            services.AddUAuthUserAuth(options => {
                configureAuth?.Invoke(options);
            });
            // 添加UAuthServer与
            services.AddMvc()
                .AddApplicationPart(typeof(UAuthServerServiceCollectionExtensions).Assembly)
                .ConfigureApplicationPartManager(manager =>
                {
                    manager.FeatureProviders.Add(new UAuthServerControllerFeatureProvider());
                });
            //services.AddAuthentication().AddScheme<CrgdJwt>
            //// 添加授权策略，使生效 AppAuthorizeAttribute生效
            //services.AddAuthorizationCore(options =>
            //{
            //    options.AddPolicy(UAuthConstants.AppAuthorizePolicyName, policy =>
            //    {
            //        policy.AuthenticationSchemes.Add(CrgdSignatureDefault.AuthenticationScheme);
            //        policy.RequireClaim(ClaimTypes.NameIdentifier);
            //    });
            //});
            services.AddHttpContextAccessor();
            services.Configure<LoginSessionOptions>(options => {});


            UAuthServerOptions serverOptions = null;
            services.Configure<UAuthServerOptions>(options => {
                configureServer.Invoke(options);
                serverOptions = options;
            });

            services.AddCors(options =>
            {
                // 允许应用前端跨域调用的策略
                options.AddPolicy(UAuthConstants.UserCorsPolicy, policy =>
                {
                    policy.SetIsOriginAllowedToAllowWildcardSubdomains();
                    policy.SetIsOriginAllowed(origin =>
                    {
                        var upperOrigin = origin.ToUpper();
                        var matchedDomainUrl = serverOptions.AppDomains.FirstOrDefault(p =>
                        {
                            return upperOrigin.StartsWith(p.Trim().ToUpper());
                        });
                        return !string.IsNullOrEmpty(matchedDomainUrl);
                    });
                    policy.AllowCredentials();
                    //policy.AllowAnyHeader();
                    policy.WithHeaders(HeaderNames.ContentType, HeaderNames.ContentLength, HeaderNames.ContentEncoding, HeaderNames.ContentDisposition);
                    policy.WithExposedHeaders(HeaderNames.ContentType);
                    policy.WithMethods(HttpMethods.Get);
                });
            });

            services.TryAddScoped<IAppServer, UAuthServer>();
            services.TryAddScoped<IVerifyCodeManager, VerifyCodeManager>();
            services.TryAddScoped<ILoginService, LoginService>();

            services.TryAddScoped<ILoginSessionManager, LoginSessionManager>();
            services.TryAddScoped<IAppManager, TAppManager>();
            services.TryAddScoped<IAppPermissionManager, TAppPermissionManager>();
            services.TryAddScoped<IUserPermissionManager, TUserPermissionManager>();
            services.TryAddScoped<IAppSecretKeyManager, TSecretKeyManager>();
            services.TryAddScoped<IUserManager, TUserManager>();
            services.TryAddScoped<ITenantManager, TTenantManager>();
            services.TryAddScoped<IDomainManager, TDomainManager>();
            services.AddHostedService<UAuthServerHostedService>();

            return services;
        }

        /// <summary>
        /// 添加文档生成器
        /// </summary>
        /// <returns></returns>
        public static IServiceCollection AddUAuthApiDoc(this IServiceCollection services)
        {
            services.AddSwaggerGen(options =>
            {
                options.SwaggerDoc("UAuthApp",
                    new OpenApiInfo() { Title = "UAuthApp", Version = "1.0" });
                //options.SwaggerDoc(UAuthServerConstants.UserApiName,
                //    new OpenApiInfo() { Title = UAuthServerConstants.UserApiName, Version = "1.0" });
                options.CustomOperationIds(e => {
                    return e.ActionDescriptor.RouteValues["action"];
                });
                options.DocInclusionPredicate((docname, desc) =>
                {
                    if (!desc.TryGetMethodInfo(out MethodInfo method))
                    {
                        return false;
                    }
                    if (docname == "UAuthApp") {
                        return method.DeclaringType == typeof(AppAuthController);
                    }
                    //if (docname == UAuthServerConstants.AppApiName)
                    //{
                    //    return method.DeclaringType == typeof(UAuthServer);
                    //}
                    return false;
                });
                var xmlFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{typeof(AppAuthController).Assembly.GetName().Name}.xml");
                options.IncludeXmlComments(xmlFile);
                //options.AddSecurityDefinition(UAuthConstants.AppAuthencitationScheme, new OpenApiSecurityScheme()
                //{
                //    Description = $@"在下框中输入请求头中需要添加{UAuthConstants.AppAuthencitationScheme}授权`Token`, 示例 Authorization: <b>&lt;{CrgdSignatureDefault.AuthenticationScheme} Token&gt;</b>，温馨提示：签名使用静态模式，Token示例：`{UAuthConstants.AppAuthencitationScheme} TestApp#TestSecret#static`，并且服务端必须开启调试模式，否则因为该签名为动态签名，将无法调用成功",
                //    Name = "Authorization",
                //    In = ParameterLocation.Header,
                //    Type = SecuritySchemeType.ApiKey,
                //    BearerFormat = "${Id}#${SecretKey}#static",
                //    Scheme = UAuthConstants.AppAuthencitationScheme,
                //});
                //options.AddSecurityRequirement(new OpenApiSecurityRequirement
                //{
                //    {
                //        new OpenApiSecurityScheme
                //        {
                //            Reference = new OpenApiReference {
                //                Type = ReferenceType.SecurityScheme,
                //                Id =  CrgdSignatureDefault.AuthenticationScheme
                //            }
                //        },
                //        new string[] { }
                //    }
                //});
                //options.AddSecurityDefinition(UAuthConstants.UserAuthencitationScheme, new OpenApiSecurityScheme()
                //{
                //    Description = $"在下框中输入请求头中需要添加{UAuthConstants.UserAuthencitationScheme}授权`Token`, 示例 Authorization: <b>&lt;{UAuthConstants.UserAuthencitationScheme} Token&gt;</b>",
                //    Name = "Authorization",
                //    In = ParameterLocation.Header,
                //    Type = SecuritySchemeType.ApiKey,
                //    Scheme = UAuthConstants.UserAuthencitationScheme,
                //});
                //options.AddSecurityRequirement(new OpenApiSecurityRequirement
                //{
                //    {
                //        new OpenApiSecurityScheme
                //        {
                //            Reference = new OpenApiReference {
                //                Type = ReferenceType.SecurityScheme,
                //                Id =  CrgdSignatureDefault.AuthenticationScheme
                //            }
                //        },
                //        new string[] { }
                //    }
                //});
            });
            return services;
        }
    }
}
